package com.smedi.ismedi.authoritymanagement.core.domain.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.AccountBasic;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.AuthorityAccess;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.AccountBasicRepository;
import com.smedi.ismedi.authoritymanagement.core.domain.service.AccountBasicDomainService;
import com.smedi.ismedi.authoritymanagement.core.domain.service.PinyinCountDomainService;
import com.smedi.ismedi.authoritymanagement.core.domain.service.RoleBasicDomainService;
import com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.web.starter.exception.LogicException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;

/**
 * @Author: xulinjun
 * @Date: 2021-7-1 21:14
 */
@Slf4j
@Service
@AllArgsConstructor
public class AccountBasicDomainServiceImpl implements AccountBasicDomainService {
    private final AccountBasicRepository accountBasicRepository;

    private final PinyinCountDomainService pinyinCountDomainService;

    private final RoleBasicDomainService roleBasicDomainService;

    /**
     * 初始化密码
     *
     * @param idCard
     * @return
     */
    private String getDefaultMD5Password(String idCard) {
        String str = idCard.substring(idCard.length() - 6);
        return SecureUtil.md5(str);
    }

    /**
     * 校验密码格式，必须要8位以上数字和字母组合
     *
     * @param password
     */
    private Boolean validatePasswordFormat(String password) {
        return Pattern.matches("^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$", password);
    }

    /**
     * 校验密码
     *
     * @param basic
     * @param newPassword
     * @return
     */
    private String validatePassword(AccountBasic basic, String newPassword) {
        // 判断当前密码是否符合格式要求
        if (!validatePasswordFormat(newPassword)) {
            throw LogicException.raise(CustomError.PASSWORD_FORMAT_ERROR);
        }
        // 判断新密码是否与老密码一致
        String md5Str = SecureUtil.md5(newPassword);
        if (basic.getPassword().equals(md5Str)) {
            throw LogicException.raise(CustomError.PASSWORD_SAME_ERROR);
        }

        return md5Str;
    }

    @Override
    public AccountBasic generateAccountBasic(AccountBasic data) {
        AccountBasic basic = new AccountBasic();

        // 创建用户名，修改为根据用户名重复增加数字位数
        try {
            String userName = pinyinCountDomainService.generateUserName(data.getLastName());
            basic.setUserName(userName).setEnable(true);
        } catch (BadHanyuPinyinOutputFormatCombination e) {
            throw LogicException.raise(CustomError.CREATE_USERNAME_ERROR, e);
        }
        basic.setPersonId(data.getPersonId())
                .setPassword(getDefaultMD5Password(data.getIdCard()))
                .setMobile(data.getMobile())
                .setEnable(true)
                .setFirst(true) // 用于首次登录需要修改密码
                .setAdmin(false) // 管理员默认都是false，只有数据库创建可以设置为true
                .setUserKey(IdUtil.simpleUUID()); // 随机号

        return accountBasicRepository.doInsert(basic);
    }

    @Override
    public void changePassword(String userKey, Long personId, String oldPassword, String newPassword) {
        AccountBasic basic = accountBasicRepository.selectByUserKeyAndPersonId(userKey, personId);
        if (basic != null) {
            // 判断用户输入的密码是否正确
            if (!basic.getPassword().equals(SecureUtil.md5(oldPassword))) {
                throw LogicException.raise(CustomError.PASSWORD_ERROR);
            }

            // 校验密码获取md5
            String md5Str = validatePassword(basic, newPassword);

            // 保存数据
            basic.setPassword(md5Str)
                    .setFirst(false);
            accountBasicRepository.doUpdate(basic);
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }

    @Override
    public void resetPassword(Long userId, String newPassword) {
        AccountBasic accountBasic = accountBasicRepository.selectByUserId(userId);
        if (accountBasic != null) {
            // 校验密码获取md5
            String md5Str = validatePassword(accountBasic, newPassword);

            // 保存数据
            accountBasic.setPassword(md5Str)
                    .setFirst(false);
            accountBasicRepository.doUpdate(accountBasic);
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }

    @Override
    public void changeMobile(String mobile, Long personId) {
        AccountBasic accountBasic = accountBasicRepository.selectByPersonId(personId);
        if (accountBasic != null) {
            if (!accountBasic.getMobile().equals(mobile)) {
                accountBasic.setMobile(mobile);
                accountBasicRepository.doUpdate(accountBasic);
            }
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }

    @Override
    public String getAccountMobile(String callAccount) {
        AccountBasic accountBasic = accountBasicRepository.selectByMobileOrUserName(callAccount);
        if (accountBasic != null) {
            return accountBasic.getMobile();
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }

    @Override
    public AccountBasic getAccountBasic(String callAccount) {
        AccountBasic accountBasic = accountBasicRepository.selectByMobileOrUserName(callAccount);
        if (accountBasic != null) {
            return accountBasic;
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }

    @Override
    public void editUserStatus(Long personId, boolean enable) {
        AccountBasic accountBasic = accountBasicRepository.selectByPersonId(personId);
        if (accountBasic != null) {
            if (accountBasic.isEnable() == enable) {
                throw LogicException.raise(CustomError.STATUS_CAN_NOT_THE_SAME);
            } else {
                accountBasic.setEnable(enable);
                accountBasicRepository.doUpdate(accountBasic);
            }
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }

    @Override
    public void deleteAccount(Long personId) {
        AccountBasic accountBasic = accountBasicRepository.selectByPersonId(personId);
        if (accountBasic != null) {
            accountBasicRepository.doDelete(accountBasic.getUserId());
        } /*else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }*/
    }

    @Override
    public AuthorityAccess login(String account, String password, String clientId) {
        AccountBasic accountBasic1 = accountBasicRepository.selectByMobileOrUserName(account);
        if (null != clientId) {
            accountBasic1.setClientId(clientId);
        }
        AccountBasic accountBasic = accountBasicRepository.doUpdate(accountBasic1);
        if (accountBasic != null) {
            // 判断当前密码是否正确
            String md5Str = SecureUtil.md5(password);
            if (!accountBasic.getPassword().equals(md5Str)) {
                throw LogicException.raise(CustomError.PASSWORD_ERROR);
            } else {
                // 判断当前用户是否生效
                if (!accountBasic.isEnable()) {
                    throw LogicException.raise(CustomError.USER_DISABLED);
                }

                // 生产token
                Snowflake snowflake = IdUtil.createSnowflake(Long.valueOf(new Random().nextInt(20) + 1), Long.valueOf(new Random().nextInt(20) + 1));  // 生成一个随机整数，范围从 1 到 20
                String token = String.valueOf(snowflake.nextId());

                // 判断是否为管理员
                boolean isAdmin = accountBasic.isAdmin();
                if (!isAdmin) {
                    // 根据角色判断是否是管理员
                    isAdmin = roleBasicDomainService.hasAdminRole(accountBasic.getPersonId());
                }

                return new AuthorityAccess().setPersonId(accountBasic.getPersonId())
                        .setUserKey(accountBasic.getUserKey())
                        .setUserName(accountBasic.getUserName())
                        .setMobile(accountBasic.getMobile())
                        .setToken(token)
                        .setLoginDateTime(LocalDateTime.now())
                        .setAdmin(isAdmin)
                        .setFirstLogin(accountBasic.isFirst())
                        .setClientId(accountBasic.getClientId()); // 是否首次登入
            }
        } else {
            throw LogicException.raise(CustomError.USER_NOT_EXIST);
        }
    }
}
